package token

import (
	"appService/src/global"
	"appService/src/libs/crypot"
	"appService/src/libs/utils"
	"errors"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/gogf/gf/frame/g"
	"strconv"
	"time"
)

//NewToken 生成新的TOKEN
func NewToken(uid string, account string, loginStr string) (string, error) {
	claims := &jwt.StandardClaims{
		Audience:  loginStr,
		NotBefore: time.Now().Unix(),
		ExpiresAt: time.Now().Unix() + global.TokenExpiresAt,
		Issuer:    "penghq",
		Id:        uid,
		Subject:   account,
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	ss, err := token.SignedString([]byte(global.TokenKeyString))
	if err != nil {
		return "", errors.New(fmt.Sprintf("生成Token错误：%v", err))
	}
	ss, err = crypot.AESEncrypt(ss)
	if err != nil {
		return "", errors.New(fmt.Sprintf("生成Token错误：%v", err))
	}
	return ss, nil
}

//CheckToken 返回：令牌是否有效，错误信息 ：： 校验token是否有效
func CheckToken(tokenStr string, callback func(uid string, account string, loginStr string)) (bool, error) {
	tokenStr, ok, err := crypot.AESDecrypt(tokenStr, true)
	if err != nil {
		g.Log().Errorf("Token解析错误：%v", err)
		return false, errors.New("令牌验证失败")
	}
	if !ok {
		g.Log().Errorf("令牌已过期")
		return false, nil
	}
	token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
		return []byte(global.TokenKeyString), nil
	})
	if err != nil {
		g.Log().Errorf("Token验证错误：%v", err)
		return false, errors.New("令牌验证失败")
	}
	//验证token，如果token被修改过则为false
	if !token.Valid {
		return false, errors.New("令牌错误")
	}
	claim, ok := token.Claims.(jwt.MapClaims)
	if !ok {
		g.Log().Errorf("Token解析结果转【jwt.MapClaims】类型失败")
		return false, errors.New("令牌解码失败")
	}
	//获取到期时间
	expStr := utils.ToString(claim["exp"])
	expiresAt, err := strconv.ParseInt(expStr, 10, 64)
	if err != nil {
		g.Log().Errorf("解析Token到期时间失败，错误：%v", err)
		return false, errors.New("令牌解码失败")
	}
	if expiresAt < time.Now().Unix() {
		g.Log().Errorf("令牌已过期")
		return false, nil
	}
	loginStr := utils.ToString(claim["aud"])
	callback(utils.ToString(claim["jti"]), utils.ToString(claim["sub"]), loginStr)
	return true, nil
}
